package com.nxy.cpfsfe;

import com.adtec.starring.datapool.EPOper;
import com.adtec.starring.exception.BaseException;
import com.adtec.starring.log.TrcLog;
import com.adtec.starring.pubmethod.Message;
import com.adtec.starring.struct.dta.DtaInfo;
import com.adtec.starring.util.SpringUtil;
import com.alibaba.fastjson.JSONObject;
import com.nxy.cpfsfe.enumtype.*;
import com.nxy.cpfsfe.mybatis.mapper.ToOrgMapper;
import com.nxy.cpfsfe.mybatis.mapper.ToPChlMapper;
import com.nxy.cpfsfe.mybatis.mapper.ToParmMapper;
import com.nxy.cpfsfe.mybatis.mapper.TsPCmdMapper;
import com.nxy.cpfsfe.mybatis.pojo.ToOrg;
import com.nxy.cpfsfe.mybatis.pojo.ToPChl;
import com.nxy.cpfsfe.mybatis.pojo.ToParm;
import com.nxy.cpfsfe.mybatis.pojo.TsPCmd;
import com.nxy.cpfsfe.util.DateUtil;
import com.nxy.cpfsfe.util.RpcCommUtil;
import com.nxy.cpfsfe.util.StringUtil;
import com.nxy.cpfsfe.util.ToPChlUtil;
import jdk.nashorn.internal.parser.JSONParser;
import org.apache.ibatis.session.SqlSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;

import java.math.BigDecimal;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;

public class PubBeanSerial {
	private static PubBeanSerial  instance = new PubBeanSerial();
	//设置为私有
	private PubBeanSerial(){}
	private final static Logger LOGGER = LoggerFactory.getLogger(PubBeanSerial.class);	

    private  SqlSession mybatisSqlSession;

    public static PubBeanSerial getInstance(){
    	return instance;
    }

    /**
     * 获取业务流水并更新序列号流水信息表
     * @return
     */
    public String getSeqNoAndIncrea(String seqNm){
    	LOGGER.info("获取[{}]流水号信息数据",seqNm);
        if(seqNm == null){
             return null;
        }	
		String currentValue = "";
		switch(seqNm){
			case "CPFSSEQ":
				try {
					//当缓存中数据不存在时候
					if(Constant.cpfsseqCurrentValue.intValue() >= Constant.cpfsseqNextValue.intValue()||Constant.cpfsseqCurrentValue.intValue() ==0){
						synchronized (PubBeanSerial.class){
							//当满足增长条件，进入同步线程
							if(Constant.cpfsseqCurrentValue.intValue() >= Constant.cpfsseqNextValue.intValue()|| Constant.cpfsseqCurrentValue.intValue() ==0){
								//获取当前序列号上限
								int var = Integer.valueOf(getSeqNoFormRpc(seqNm));
								if(Constant.cpfsseqNextValue.compareAndSet(Constant.cpfsseqCurrentValue.intValue() ,var)){
									Constant.cpfsseqCurrentValue = new AtomicInteger(Constant.cpfsseqNextValue.intValue() -100);
								}
							}

						}
					}
					currentValue = String.valueOf(Constant.cpfsseqCurrentValue.getAndIncrement());
					String date   = DateUtil.getDate();
					currentValue=date+Constant.SER_003+getSeqNo(currentValue,7);
				} catch (Exception e) {
					LOGGER.error("CPFSSEQ流水号生成失败",e);
					throw new BaseException(RespCd.NCPO6049,e,"CPFSSEQ流水号生成失败");
				}
				break;
			case "MSGID":
				try {
					//当缓存中数据不存在时候
					if(Constant.msgIdCurrentValue.intValue() >= Constant.msgIdNextValue.intValue()||Constant.msgIdCurrentValue.intValue() ==0){
						synchronized (PubBeanSerial.class){
							//当满足增长条件，进入同步线程
							if(Constant.msgIdCurrentValue.intValue() >= Constant.msgIdNextValue.intValue()|| Constant.msgIdCurrentValue.intValue() ==0){
								//获取当前序列号上限
								int var = Integer.valueOf(getSeqNoFormRpc(seqNm));
								if(Constant.msgIdNextValue.compareAndSet(Constant.msgIdCurrentValue.intValue() ,var)){
									Constant.msgIdCurrentValue = new AtomicInteger(Constant.msgIdNextValue.intValue() -100);
								}
							}

						}
					}
					currentValue = String.valueOf(Constant.msgIdCurrentValue.getAndIncrement());
					ToPChl topChl =getChlDate();
					if(topChl !=null){
						currentValue=DateUtil.date4Str(topChl.getpCD())+Constant.SER_003+getSeqNo(currentValue,7);
					}
				} catch (Exception e) {
					LOGGER.error("MSGID流水号生成失败",e);
					throw new BaseException(RespCd.NCPO6049,e,"MSGID流水号生成失败");
				}
				break;
			case "seqNb":
				//当缓存中数据不存在时候
				if(Constant.seqnbCurrentValue.intValue() >= Constant.seqnbNextValue.intValue()||Constant.seqnbCurrentValue.intValue() ==0){
					synchronized (PubBeanSerial.class){
						//当满足增长条件，进入同步线程
						if(Constant.seqnbCurrentValue.intValue() >= Constant.seqnbNextValue.intValue()|| Constant.seqnbCurrentValue.intValue() ==0){
							//获取当前序列号上限
							int var = Integer.valueOf(getSeqNoFormRpc(seqNm));
							if(Constant.seqnbNextValue.compareAndSet(Constant.seqnbCurrentValue.intValue() ,var)){
								Constant.seqnbCurrentValue = new AtomicInteger(Constant.seqnbNextValue.intValue() -100);
							}
						}

					}
				}
				currentValue = String.valueOf(Constant.seqnbCurrentValue.getAndIncrement());
				Date date = new Date();
				currentValue =DateUtil.date2Str(date, "dd")+StringUtil.getSeqNo(SysEcodeEnum.CPFS.getCode(), 6, false)+StringUtil.getSeqNo(currentValue,7);
				break;
			case "CPFS":
				//当缓存中数据不存在时候
				String dateString = DateUtil.getDate();
				currentValue = new StringBuffer(dateString).append(seqNm).append(getSeqNo(currentValue,7)).toString();
				break;
			case "NGPS":
				try {
					ToPChl topChl =getChlDate();
					if(topChl !=null){
						currentValue = getSeqNoFormRpc(seqNm);
						currentValue=DateUtil.date4Str(topChl.getpCD())+Constant.SER_001+getSeqNo(currentValue,7);
					}
				} catch (Exception e) {
					LOGGER.error("MSGID流水号生成失败",e);
					throw new BaseException(RespCd.NCPO6049,e,"NGPS_MSGID流水号生成失败");
				}
				break;
			case "NVAS":
				try {
					ToPChl topChl =getChlDate();
					if(topChl !=null){
						currentValue = getSeqNoFormRpc(seqNm);
						currentValue=DateUtil.date4Str(topChl.getpCD())+Constant.SER_002+getSeqNo(currentValue,7);
					}
				} catch (Exception e) {
					LOGGER.error("MSGID流水号生成失败",e);
					throw new BaseException(RespCd.NCPO6049,e,"NVAS_MSGID流水号生成失败");
				}
				break;

			default:
				currentValue = getSeqNoFormRpc(seqNm);
				currentValue = new StringBuffer(currentValue).toString();
			}
		
	  	LOGGER.debug("获得序列号信息currentValue = {}" , currentValue);

        return currentValue;
    }

	/**
	 * 从通用体系获取流水号信息
	 * @param seqNm
	 * @return
	 */
	public String getSeqNoFormRpc(String seqNm){
		String tpId =DtaInfo.getInstance().getTpId();
		EPOper.put(tpId, "ReqBean[0].head[0].servEcd","mQry_SeqSn");
		DtaInfo dtaInfo = DtaInfo.getInstance();
		Message msg = (Message) dtaInfo.getMessage();
		Map<String, Object> msgMap = new HashMap<String,Object>();
		msgMap.put("seqNm", seqNm);
		msg.setBody(msgMap);
		String seqNo =RpcCommUtil.getInstance().rpcFeToSms(tpId, RpcOutputInfoEnum.Pub_Sms_Output.getCode(), RpcOutputInfoEnum.Sms_Svr_SeqSn.getCode());
		return seqNo;
	}

	/**
	 * 获取账务日期
	 * @return
	 */
	private ToPChl getChlDate(){
		mybatisSqlSession =(SqlSession) SpringUtil.getBean("mybatisSqlSession");
		ToPChlMapper tChlMapper = mybatisSqlSession.getMapper(ToPChlMapper.class);
		ToPChl topChl = new ToPChl();
		//topchal通道信息表查询条件
		topChl.setpCId(SysEcodeEnum.NCS.getCode());
		topChl=tChlMapper.query(topChl);
		return topChl;
	}

    /**
     * 支付流水信息表数据库入库操作
     * @param map
     * @return
     */
    public int insertBySerivalMap(Map<String,String>  map){
		mybatisSqlSession=(SqlSession) SpringUtil.getBean("mybatisSqlSession");
		int num= 0;
		try {
			Date date = ToPChlUtil.getInstance().getToPChlByPcId(SysEcodeEnum.NCS.getCode()).getpCD();
			TsPCmd pCmd = new TsPCmd();
			pCmd.setCpfsD(date);
			pCmd.setMsgTp(StringUtil.trimObject(map.get("/root/MsgHeader/MsgTp")));
			pCmd.setCpfsSeqNo(map.get("currentValue"));
			pCmd.setBizSysD(DateUtil.str2Date(map.get("/root/MsgHeader/SndDt"), "yyyy-MM-dd HH:mm:ss"));
			pCmd.setComId(StringUtil.trimObject(map.get("/root/MsgHeader/MsgTp")));
			pCmd.setComMsgId(StringUtil.trimObject(map.get("/root/MsgHeader/CorrId")));
			pCmd.setBizSysId(StringUtil.trimObject(map.get("/root/MsgHeader/SndSysId")));
			pCmd.setXSeqNo(StringUtil.trimObject(map.get("/root/MsgHeader/TrxId")));
			pCmd.setBizSta(StringUtil.trimObject(StatEnum.BIZSTA_INIT.getCode()));
			pCmd.setBizTyp(StringUtil.trimObject(map.get("/root/MsgBody/TrxInf/TrxCtgy")));
			pCmd.setBizCls(StringUtil.trimObject(map.get("/root/MsgBody/TrxInf/BizKind")));
//			pCmd.setEndToEndId(StringUtil.trimObject(map.get("endToEndId")));
			String sndBankId = StringUtil.trimObject(map.get("/root/MsgHeader/SndBankId"));
			String orgBNo = null;
			if(sndBankId.length() == 12){
				orgBNo = sndBankId;
			}else if(sndBankId.length() ==4){
				if(BnknoCdEnum.BNKNOCD_0000.getCode().equals(sndBankId)){
					ToParmMapper toParmMapper = mybatisSqlSession.getMapper(ToParmMapper.class);
					ToParm toParm = new ToParm();
					toParm.setDataCd(StringUtil.trimObject(map.get("/root/MsgHeader/SndSysId")));
					toParm.setDataTyp(DataTypeEnum.BIZSYS.getCode());
					List<ToParm> list = toParmMapper.query(toParm);
					if(list != null){
						if(list.size()==1){
							orgBNo = list.get(0).getDataVal();
						}else{
							throw new BaseException(RespCd.NCPO0007,"参数信息表数据异常"+sndBankId);
						}
					}else{
						throw new BaseException(RespCd.NCPO0007,"发送行不正确："+sndBankId+",或参数信息表未定义");

					}
				}else{
					ToOrgMapper toOrgMapper = mybatisSqlSession.getMapper(ToOrgMapper.class);
					ToOrg toOrg = new ToOrg();
					toOrg.setOrgId(sndBankId);
					toOrg.setOrgCls("1");
					List<ToOrg> list = toOrgMapper.query(toOrg);
					if(list != null){
						if(list.size()==1){
							orgBNo = list.get(0).getOrgBNo();
						}else{
							throw new BaseException(RespCd.NCPO0007,"机构信息表数据异常"+sndBankId);
						}
					}else{
						throw new BaseException(RespCd.NCPO0007,"发送行不正确："+sndBankId+",或机构信息表未定义");

					}
				}
			}else{
				throw new BaseException(RespCd.NCPO0007,"发送行不正确："+sndBankId+",位数非法");
			}
			pCmd.setShardingId(orgBNo);
			pCmd.setAcqOrgId(orgBNo);
			pCmd.setSndBNo(sndBankId);
			pCmd.setRcvBNo(StringUtil.trimObject(map.get("/root/MsgHeader/RcvBankId")));
			pCmd.setOrdAmt(new BigDecimal(StringUtil.trimObject(map.get("/root/MsgBody/TrxInf/TrxAmt"))));
			pCmd.setFeFlg(StringUtil.trimObject(map.get("/root/MsgBody/TrxInf/TrxFeeFlg")));
			pCmd.setFeAmt(new BigDecimal(StringUtil.trimObject(map.get("/root/MsgBody/TrxInf/TrxFeeAmt"))));
			pCmd.setCashRmFlg(StringUtil.trimObject(map.get("/root/MsgBody/TrxInf/TrxCashTp")));
			pCmd.setCurTyp(StringUtil.trimObject(map.get("/root/MsgBody/TrxInf/TrxCurTp")));
			pCmd.setpTms(1);
			pCmd.setpInfo(StringUtil.trimObject(map.get("/root/MsgBody/TrxInf/TrxPurPose")));
			//将交易摘要TrxUstrd、nginx地址、回调地址组成json串存入addinfo
			Map<String ,Object> jsonMap = new HashMap<String,Object >();
			jsonMap.put("ClbckUrl",StringUtil.trimObject(map.get("/root/MsgHeader/ClbckUrl")));
			jsonMap.put("TrxUstrd",StringUtil.trimObject(map.get("/root/MsgBody/TrxInf/TrxUstrd")));
			jsonMap.put("NginxUrl",StringUtil.trimObject(map.get("NginxUrl")));
			JSONObject jsonObject = new JSONObject(jsonMap);
			pCmd.setAddInfo(jsonObject.toJSONString());
//			pCmd.setRespMsgId("");
			pCmd.setChkASta(StatEnum.CHKASTA_NOT_START.getCode());
			Date nowDate = new Date();
			Timestamp tmp = new Timestamp(nowDate.getTime());
			pCmd.setCreTm(tmp);
			pCmd.setUpdTm(tmp);
			TsPCmdMapper tsPCmd = mybatisSqlSession.getMapper(TsPCmdMapper.class);
			num=tsPCmd.insertByPo(pCmd);
			if(num != 1){
				throw new BaseException(RespCd.NCPS5002,"数据库操作失败：支付流水表TsPCmd更新数不正确");
			}
		}catch(DataAccessException e){
			int a =((SQLException) e.getCause()).getErrorCode();
			DBErrorCdEnum dberr = DBErrorCdEnum.getEnum(a+"");
			map.put("msg", dberr.getDesc());
			map.put("resultCode",dberr.getName());
			LOGGER.error("数据库入库失败，失败原因[{}]",dberr.getDesc());
			throw new BaseException(RespCd.NCPS5002,e,dberr.getDesc());
		} catch (Exception e) {
			throw new BaseException(RespCd.NCPS5002,e,"未知异常，请联系管理员");
		}
    	return num;

    }

   

    /**
     * 获取指定位数的流水信息
     * @param seqNo
     * @param size
     * @return
     */
    public  String getSeqNo(String seqNo, int size) {
        while (seqNo.length() < size) {
            seqNo = "0" + seqNo;
        }
        return seqNo;
    }


}
